package de.jmda.fx.node.behaviour;

import javafx.scene.Node;


public class DraggingCalculatorDefault implements DraggingCalculator
{
	/**
	 * injected into constructor
	 */
	private BehaviourMouseDraggingConstraint draggingConstraint;

	/**
	 * injected into constructor
	 */
	private Node node;

	/**
	 * injected into constructor
	 */
	private DraggingData draggingRequest;
	
	/**
	 * calculated based on injected data
	 */
	private DraggingData draggingResponse;

	public DraggingCalculatorDefault(
			Node node,
			DraggingData draggingRequest,
	    BehaviourMouseDraggingConstraint draggingConstraint)
	{
		super();

		this.node = node;
		this.draggingRequest = draggingRequest;
		this.draggingConstraint = draggingConstraint;
		
		draggingResponse = calculate();
	}

	@Override
  public DraggingData calculate()
  {
		if (draggingResponse == null)
		{
			draggingResponse =
					new DraggingData(calulateXDragging(), calulateYDragging());
		}

		return draggingResponse;
  }

	public double calulateXDragging()
	{
		if (draggingRequest.getDragX() < 0)
		{
			return calculateXDraggingLeft(draggingRequest.getDragX());
		}
		
		return calculateXDraggingRight(draggingRequest.getDragX());
	}

	public double calulateYDragging()
	{
		if (draggingRequest.getDragY() < 0)
		{
			return calculateYDraggingUp(draggingRequest.getDragY());
		}
		
		return calculateXDraggingDown(draggingRequest.getDragY());
	}

	/**
	 * <b>remember that in contrast to {@link #calculateXDraggingRight(double)}
	 * <code>dragX</code> is negative</b>
	 * 
	 * @param dragX
	 * @return
	 */
	private double calculateXDraggingLeft(double dragX)
  {
		double nodeMinX = node.getBoundsInParent().getMinX();

		if (nodeMinX < draggingConstraint.getMinX())
		{
			// already beyond draggingConstraint.minX, no further dragging left
			return 0;
		}
		
		if ((nodeMinX + dragX) < draggingConstraint.getMinX())
		{
			// if dragX was applied node would move beyond draggingConstraint.minX, so
			// drag no further than draggingConstraint.minX
			return nodeMinX - draggingConstraint.getMinX();
		}

		return dragX;
  }

	/**
	 * <b>remember that in contrast to {@link #calculateXDraggingLeft(double)}
	 * <code>dragX</code> is positive</b>
	 * 
	 * @param dragX
	 * @return
	 */
	private double calculateXDraggingRight(double dragX)
  {
		double nodeMaxX = node.getBoundsInParent().getMaxX();

		if (nodeMaxX > draggingConstraint.getMaxX())
		{
			// already beyond draggingConstraint.maxX, no further dragging right
			return 0;
		}
		
		if ((nodeMaxX + dragX) > draggingConstraint.getMaxX())
		{
			// if dragX was applied node would move beyond draggingConstraint.maxX, so
			// drag no further than draggingConstraint.maxX
			return draggingConstraint.getMaxX() - nodeMaxX;
		}

		return dragX;
  }

	/**
	 * <b>remember that in contrast to {@link #calculateYDraggingDown(double)}
	 * <code>dragY</code> is negative</b>
	 * 
	 * @param dragY
	 * @return
	 */
	private double calculateYDraggingUp(double dragY)
  {
		double nodeMinY = node.getBoundsInParent().getMinY();

		if (nodeMinY < draggingConstraint.getMinY())
		{
			// already beyond draggingConstraint.minY, no further dragging up
			return 0;
		}
		
		if ((nodeMinY + dragY) < draggingConstraint.getMinY())
		{
			// if dragY was applied node would move beyond draggingConstraint.minY, so
			// drag no further than draggingConstraint.minY
			return nodeMinY - draggingConstraint.getMinY();
		}

		return dragY;
  }

	/**
	 * <b>remember that in contrast to {@link #calculateYDraggingUp(double)}
	 * <code>dragY</code> is positive</b>
	 * 
	 * @param dragY
	 * @return
	 */
	private double calculateXDraggingDown(double dragY)
  {
		double nodeMaxY = node.getBoundsInParent().getMaxY();

		if (nodeMaxY > draggingConstraint.getMaxY())
		{
			// already beyond draggingConstraint.maxY, no further dragging down
			return 0;
		}
		
		if ((nodeMaxY + dragY) > draggingConstraint.getMaxY())
		{
			// if dragY was applied node would move beyond draggingConstraint.maxY, so
			// drag no further than draggingConstraint.maxY
			return draggingConstraint.getMaxY() - nodeMaxY;
		}

		return dragY;
  }
}